@file:JvmMultifileClass
@file:JvmName("ListUtils")

package hos.kotlin

/**
 * <p>Title: IterableExt </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @date : 2024-07-12 11:42
 * @version : 1.0
 */

public inline fun <T> Collection<T>?.count(action: T?.(index: Int) -> Boolean): Int {
    if (isNullOrEmpty()) {
        return 0
    }
    var count = 0
    forEachIndexed { index, t ->
        if (action(t, index)) {
            count++
        }
    }
    return count
}

fun <T> Iterable<T>.includes(item: T?): Boolean {
    return contains(item)
}

fun <T> Collection<T>?.isNull(index: Int): Boolean {
    if (isNullOrEmpty() || size <= index) {
        return true
    }
    try {
        val element = elementAt(index);
        return element == null ||
                "null" == element ||
                "NULL" == element ||
                "Null" == element
    } catch (_: Throwable) {
    }
    return true
}

@JvmOverloads
fun <T> Collection<T>?.getValue(
    index: Int,
    defaultValue: T? = null,
    convert: (T.() -> T)? = null
): T? {
    if (isNull(index)) {
        return defaultValue
    }
    return try {
        val value = this?.elementAt(index) ?: return defaultValue
        return convert?.invoke(value) ?: return value
    } catch (_: Throwable) {
        defaultValue
    }
}

@JvmOverloads
fun <T> Collection<T>?.getString(
    index: Int,
    defaultValue: String? = null,
    convert: (T.() -> String)?=null
): String? {
    val value = getValue(index) ?: return defaultValue
    if (value is String) {
        return value
    }
    return convert?.invoke(value) ?: value.toString()
}

@JvmOverloads
fun <T> Collection<T>?.optString(
    index: Int,
    defaultValue: String = "",
    convert: (T.() -> String)
): String {
    return getString(index, defaultValue, convert) ?: defaultValue
}

@JvmOverloads
fun <T> Collection<T>?.getInt(
    index: Int,
    defaultValue: Int? = null,
    convert: (T.() -> Int)?=null
): Int? {
    val value = getValue(index) ?: return defaultValue
    if (value is Int) {
        return value
    }
    return convert?.invoke(value) ?: value.toString().toIntOrNull()
}

@JvmOverloads
fun <T> Collection<T>?.optInt(
    index: Int,
    defaultValue: Int = 0,
    convert: (T.() -> Int)?=null
): Int {
    return getInt(index,defaultValue,convert) ?: return defaultValue
}

@JvmOverloads
fun <T> Collection<T>?.getDouble(
    index: Int,
    defaultValue: Double? = null,
    convert: (T.() -> Double)?=null
): Double? {
    val value = getValue(index) ?: return defaultValue
    if (value is Double) {
        return value
    }
    return convert?.invoke(value) ?: value.toString().toDoubleOrNull()
}

@JvmOverloads
fun <T> Collection<T>?.optDouble(
    index: Int,
    defaultValue: Double = 0.0,
    convert: (T.() -> Double)?=null
): Double {
    return getDouble(index,defaultValue,convert) ?: return defaultValue
}

@JvmOverloads
fun <T> Collection<T>?.getFloat(
    index: Int,
    defaultValue: Float? = null,
    convert: (T.() -> Float)?=null
): Float? {
    val value = getValue(index) ?: return defaultValue
    if (value is Float) {
        return value
    }
    return convert?.invoke(value) ?: value.toString().toFloatOrNull()
}

@JvmOverloads
fun <T> Collection<T>?.optFloat(
    index: Int,
    defaultValue: Float = 0.0f,
    convert: (T.() -> Float)?=null
): Float {
    return getFloat(index,defaultValue,convert) ?: return defaultValue
}

@JvmOverloads
fun <T> Collection<T>?.getBoolean(
    index: Int,
    defaultValue: Boolean? = null,
    convert: (T.() -> Boolean)?=null
): Boolean? {
    val value = getValue(index) ?: return defaultValue
    if (value is Boolean) {
        return value
    }
    return convert?.invoke(value) ?: value.toString().toBooleanStrictOrNull()
}

@JvmOverloads
fun <T> Collection<T>?.optBoolean(
    index: Int,
    defaultValue: Boolean = false,
    convert: (T.() -> Boolean)?=null
): Boolean {
    return getBoolean(index,defaultValue,convert) ?: return defaultValue
}

public inline fun <T> Collection<T>?.forEachCanBreak(action: T?.(index: Int) -> Boolean) {
    if (this == null) {
        return
    }
    for ((index, t) in this.withIndex()) {
        if (action(t, index)) {
            break
        }
    }
}

public inline fun <T> Collection<T>?.where(action: T?.(index: Int) -> Boolean): MutableList<T> {
    if (this == null) {
        return mutableListOf()
    }
    val list = mutableListOf<T>()
    for ((index, t) in this.withIndex()) {
        if (action(t, index)) {
            list.add(t)
        }
    }
    return list
}

fun <T> Collection<T>?.like(index: Int): String {
    return optString(index, "%%") {
        return@optString "%$this%"
    }
}